using System;
using System.Xml.Serialization;

#if Use_Common_MudLib
using SharpMud.MudLib.Common.Environment;
using SharpMud.MudLib.Common.Environment.Persistance;
using SharpMud.MudLib.Common.Entities;
#else
using SharpMud.MudLib.SAMPLE.Entities;
#endif
using SharpMud.MudLib.SAMPLE.Environment;

namespace SharpMud.MudLib.SAMPLE.Environment
{
	/// <summary>
	/// Represents a room in the world
	/// </summary>
	[XmlRoot("Room")]
	public class Room
		: IDescribable, IDisposable
	{
		#region Private Variables
		private System.Collections.ArrayList	_CharactersHere;
		private System.Collections.ArrayList	_ItemsHere;
		private System.Collections.ArrayList	_Exits;
		private RoomID							_RoomID;
		private bool							_AllowViolence;
		private string							_ShortDescription;
		private string							_LongDescription;
		private Area							_Area;
		#endregion

		#region Initialization and Instanciation
		public Room()
		{
			_CharactersHere = new System.Collections.ArrayList();
			_Exits = new System.Collections.ArrayList();
			_Area = null;
		}

		public void Initialize(Area area)
		{
			_Area = area;
			foreach(IExit e in this.Exits)
			{
				Room r = _Area.HostEnvironSystem.GetRoom(e.TargetRoom);
				
				if(r==null)
					throw new RoomNotFoundException(e.TargetRoom);

				e.TargetRoom.Value = r.RoomID.Value;
			}
		}

		#endregion
		
		#region Simple Standard Properties

		[XmlIgnore()]
		public Area Area
		{
			get
			{
				return _Area;
			}
		}
		

		/// <summary>
		/// The ID of this room
		/// </summary>
		[XmlElement("RoomID")]
		public RoomID RoomID
		{
			get
			{
				return this._RoomID;
			}
			set
			{
				this._RoomID = value;
			}
		}

		/// <summary>
		/// The short description of this room. A title of sorts.
		/// </summary>
		[XmlElement("ShortDescription")]
		public string ShortDescription
		{
			get
			{
				return _ShortDescription;
			}
			set
			{
				_ShortDescription = value;
			}
		}
		
		/// <summary>
		/// The long description of this room. The static portion.
		/// </summary>
		[XmlElement("LongDescription")]
		public string LongDescription
		{
			get
			{
				return _LongDescription;
			}
			set
			{
				_LongDescription = value;
			}
		}

		/// <summary>
		/// Whether or not characters in this room may commit acts of violence or agression in this room.
		/// </summary>
		[XmlElement("AllowViolence")]
		public bool AllowViolence
		{
			get
			{
				return _AllowViolence;
			}
			set
			{
				_AllowViolence = value;
			}
		}

		#endregion

		#region Exits
		/// <summary>
		/// The exits leading out of this room
		/// </summary>
		[XmlIgnore()]
		public IExit[] Exits
		{
			get
			{
				return (IExit[])_Exits.ToArray(typeof(IExit));
			}
			set
			{
				_Exits.AddRange(value);
			}
		}

		
		public SimpleDirectionalExit[] DirectionalExits
		{
			get
			{
				return (SimpleDirectionalExit[])_Exits.ToArray(typeof(SimpleDirectionalExit));
			}
			set
			{
				_Exits.AddRange(value);
			}
		}
		
		[XmlIgnore()]
		public System.Collections.ArrayList ExitCollection
		{
			get
			{
				return this._Exits;
			}
		}
		#endregion

		#region Characters Here

		/// <summary>
		/// Gets all of the characters that are in this room
		/// </summary>
		/// <returns>Returns an array of ICharacter</returns>
		public Entities.ICharacter[] GetCharactersHere()
		{
			return (Entities.ICharacter[])_CharactersHere.ToArray(typeof(Entities.ICharacter));
		}

		/// <summary>
		/// Registers that a character is in this room. Raises any appropriate events,
		/// but does not communicate the change to the inhabitants of the room.
		/// </summary>
		/// <param name="character"></param>
		public void RegisterCharacterHere(Entities.ICharacter character)
		{
			if(! this._CharactersHere.Contains(character))
			{
				this._CharactersHere.Add(character);
			}
			character.Location = new RoomID(this);
		}

		/// <summary>
		/// Removes a character from the room. Raises any appropriate events,
		/// but does not communicate the change to the inhabitants of the room.
		/// </summary>
		/// <param name="character"></param>
		public void DeregisterCharacterFromHere(Entities.ICharacter character)
		{
			this._CharactersHere.Remove(character);
			character.Location = RoomID.Empty;
		}

		#endregion

        [XmlIgnore]
		public IDescribable[] DescribableContents
		{
			get
			{
				System.Collections.ArrayList al = new System.Collections.ArrayList();
				al.AddRange(this.GetCharactersHere());
				//al.AddRange(this.GetItemsHere());
				al.AddRange(this.Exits);
				return (IDescribable[])al.ToArray(typeof(IDescribable));
			}
		}


		#region IDescribable Members

		/// <summary>
		/// Gets the short description (title) of the room.
		/// </summary>
		/// <remarks>
		/// This function's results could possibly contain text formatting triggers, but it should never
		/// include active MXP tags such as for links, or markup to designate what kind of content it is.
		/// </remarks>
		public string GetShortDescription(ICharacter looker)
		{
			return this.ShortDescription;
		}

		/// <summary>
		/// This dynamically gets a full, long, description of the room. Used for the primary body of
		/// text during a look command. Includes sub-items ( GetIntegralShortDescription() ) 
		/// incorporated from IDescribable contents.
		/// </summary>
		/// <remarks>
		/// This function's results will probably contain text formatting triggers, but it should never
		/// include active MXP tags such as for links, or markup to designate what kind of content it is.
		/// </remarks>
		public string GetLongDescription(ICharacter looker)
		{
			System.Text.StringBuilder sb = new System.Text.StringBuilder(this.LongDescription.Trim());
			string s;
			foreach(IDescribable i in this.DescribableContents)
			{
				s = i.GetIntegralShortDescription(looker);
				if(s==null)
					continue;
				if(s==String.Empty)
					continue;
				if(s.Trim()==String.Empty)
					continue;
				sb.Append(' ');
				sb.Append(s);
			}
			return sb.ToString();
		}

		/// <summary>
		/// This IDescribable form is not supported for a room. If this is called, then there is
		/// a serious problem going on anyway.
		/// </summary>
		public string GetDeclarativeShortDescription(ICharacter looker)
		{
			throw new NotImplementedException();
		}

		/// <summary>
		/// This IDescribable form is not supported for a room. If this is called, then there is
		/// a serious problem going on anyway.
		/// </summary>
		public string GetIntegralShortDescription(ICharacter looker)
		{
			throw new NotImplementedException();
		}
		#endregion

        #region IDisposable Members

        public void Dispose()
        {
            foreach (IDisposable d in _Exits)
            {
                d.Dispose();
            }
            foreach (IDisposable d in _ItemsHere)
            {
                d.Dispose();
            }
            foreach (IDisposable d in _CharactersHere)
            {
                d.Dispose();
            }
        }

        #endregion
    }

#if !Use_Common_MudLib
	public delegate void RoomIDChangedHandler(RoomID sender);
#else
    public delegate void RoomIDChangedHandler(RoomReference sender);
#endif
}
